import os
import pin
import assembly as ASM

dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'micro.bin')

micro = [pin.HLT for _ in range(0x10000)]

def compile_addr2(addr, ir, psw, index):
    global micro
    
    # addr ==> | IR | PSW | CYC |
    # 二地址指令IR对应 ==> 1xxx [aa][bb]
    op = ir & 0xf0
    amd = (ir >> 2) & 3 # [aa] 寻址方式
    ams = ir & 3 # [bb] 寻址方式
    
    INST = ASM.INSTRUCTIONS[2]
    if op not in INST:
        micro[addr] = pin.CYC
        return
    am = (amd, ams)
    if am not in INST[op]:
        micro[addr] = pin.CYC
        return
    
    EXEC = INST[op][am] # 找到IR和寻址方式
    if index < len(EXEC): # 补到FETCH后面
        micro[addr] = EXEC[index]
    else:
        micro[addr] = pin.CYC

# 01xx xx[bb]
def compile_addr1(addr, ir, psw, index):
    global micro
    
    # addr ==> | IR | PSW | CYC |
    # 一地址指令IR对应 ==> 01xx xx[bb]
    op = ir & 0xfc
    amd = ir & 3 # [bb] 寻址方式
    
    INST = ASM.INSTRUCTIONS[1]
    if op not in INST:
        micro[addr] = pin.CYC
        return
    if amd not in INST[op]:
        micro[addr] = pin.CYC
        return
    
    EXEC = INST[op][amd] # 找到IR和寻址方式
    if index < len(EXEC): # 补到FETCH后面
        micro[addr] = EXEC[index]
    else:
        micro[addr] = pin.CYC

# 00xx xxxx
def compile_addr0(addr, ir, psw, index):
    global micro
    
    op = ir

    INST = ASM.INSTRUCTIONS[0]
    if op not in INST:
        micro[addr] = pin.CYC
        return
    
    EXEC = INST[op]
    if index < len(EXEC):
        micro[addr] = EXEC[index]
    else:
        micro[addr] = pin.CYC

for addr in range(0x10000): # 指令集处理
    # | IR | PSW | CYC |
    #   8     4     4
    ir = addr >> 8
    psw = (addr >> 4) & 0xf
    cyc = addr & 0xf
    
    # 先处理 取指指令FETCH
    if cyc < len(ASM.FETCH):
        micro[addr] = ASM.FETCH[cyc]
        continue
    
    addr2 = ir & (1 << 7) # 二地址
    addr1 = ir & (1 << 6) # 一地址
    
    index = cyc - len(ASM.FETCH) # FETCH占据了前面的位置，这里表示FETCH后面
    
    if addr2:
        compile_addr2(addr, ir, psw, index) # 处理二地址
    elif addr1:
        compile_addr1(addr, ir, psw, index) # 处理一地址
    else:
        compile_addr0(addr, ir, psw, index) # 处理零地址

with open(filename, 'wb') as file:
    for var in micro:
        value = var.to_bytes(4, byteorder='little')
        file.write(value)

print('Compile micro instruction finish!!!')
